<?php
/**
 * huhaiqin,2024.10.11
 * 短信逻辑代码，腾讯的版本
 */
namespace Common\Model;
use Think\Model;
class SmsModel extends Model{

    // 使用的是腾讯的短信通道,短信通道配置
    private $config = [
        'SecretId'      => 'AKIDPedMoztXu2tTmoZ4IFwShgOp0uXtymJZ',
        'SecretKey'     => '1lERN2QbV9WbQzGGzRdYCZfV3KL5YkfJ',
        'host'          => 'sms.tencentcloudapi.com',
        'Region'        => 'ap-guangzhou',
        'Version'       => '2021-01-11',
        'SmsSdkAppId'   => '1400616575',
        'Action'        => 'SendSms', //默认调用发送短信通道
        'SignName'      => '蓝莓互动小程序',
        'TemplateId'    => '1257241',
        'Timestamp'     => 0,
        'Nonce'         => 0
    ];
    private $limitTime = 10 * 60; //重发限制时间，默认10分钟

    /**
     * huhaiqin,2024.10.13
     * 生成发送短信的token，利用session = uuid()
     */
    public function create_token(){
        return $_SESSION['SMS_TOKEN'] = uuid();
    }

    /**
     * huhaiqin,2024.10.13
     * 检测token是否正确
     */
    public function check_token($token = ''){
        if($token != '' && $_SESSION['SMS_TOKEN'] == $token){
            unset($_SESSION['SMS_TOKEN']); //销毁token
            return true;
        }
        return false;
    }


    /**
     * huhaiqin,2024.10.11
     * 发送短信
     */
    public function send_sms($mobile = '',$token = '',$type = 'check'){
        // 校验$mobile
        if ($mobile == '') {
            _apiReturn(0, '手机号码不能为空~');
        }
        if (!check_phone($mobile)) {
            _apiReturn(0, '手机号码格式不正确~');
        }

        if(!check_token($token)){
            _apiReturn(0,'非法调用~');
        }
        // 检测一下是否需要重发
        $checkResult = $this->_check_has_send($mobile,$type); //前面已经校验了mobile,不可能是 -1
        if($checkResult == 1){
            // 发送验证码
            // 补全短信配置参数
            $code = (string)mt_rand(100000,999999); //生成一个随机数
            $this->config['Timestamp'] = time();
            $this->config['Nonce'] = mt_rand(); 
            $this->config["TemplateParamSet.0"] = $code;
            $this->config["PhoneNumberSet.0"] = $mobile;
            //调用私有函数，发送短信
            $checkSend = $this->_send_sms($this->config); 
            if($checkSend['Code'] == 'Ok'){
                //表示发送成功，需要往数据库存储数据
                $data = [
                    'mobile'      => $mobile,
                    'code'        => $code,
                    'type'        => $type,
                    'status'      => 1,
                    'is_used'     => 0,
                    'create_time' => time()
                ];
                if($this->add($data)){
                    _apiReturn(1,'success');
                }else{
                    _apiReturn(0,'数据创建失败');
                }
            }else{
                _apiReturn(0,'对不起，短信发送失败');
            }
            return ;
        }
        _apiReturn(0,'验证码已发送，尚未过期~'); 
    }

    /**
     * huhaiqin,2024.10.11
     * 校验验证码，只能校验一次，校验过后就实现
     * return boolean , 以便实现其他业务
     */
    public function check_code($mobile = '',$code = '',$type = 'check'){
        if(!$mobile || !check_phone($mobile)){
            _apiReturn(0,'手机号码格式错误~');
        }
        if($code == ''){
            _apiReturn(0,'验证码不能为空~');
        }
        // 匹配条件
        $map = [
            'mobile'  => $mobile,
            'code'    => $code,
            'is_used' => 0,
            'type'   => $type
        ];
        $check = $this->where($map)->order('id desc')->find(); //确保查出来的是最新的那条数据
        if($check){
            // 检测是否过期
            if((time() - $check['create_time']) <= $this->limitTime){
                //没有过期，表示验证码正确，改数据
                $this->where(['id' => $check['id']])->save(['is_used' => 1]); //标记该短信已被使用
                return 1;
            }else{
                return -1;
            }
        }
        return 0;
    }

    /**
     * huhaiqin,2024.10.11
     * 私有方法，检测是否已经发送过短信
     */
    private function _check_has_send($mobile = '',$type = 'check'){
        //查询条件
        $map = [
            'mobile'  => $mobile,//手机号码
            'type'    => $type,  //验证类型
            'is_used' => 0,      //没被使用过
            'status'  => 1       //短信需要发送成功的
        ];
        $check = $this->where($map)->find();
        if(!$check){
            return 1; //没记录，就是可以发
        }
        //有记录，那么就看看过期了没
        if((time() - $check['create_time']) > $this->limitTime ){
            return 1; //短信已经过期，可以重发
        }
        return 0; //不满足重发条件
    }

    /**
     * huhaiqin，2024.10.11
     * 私有方法，根据给的参数发送短信
     * 改编制杜国俊提供的方法
     */
    private function _send_sms($param){
        // 提出来两个不参与生成sign的参数
        $secretKey = $param['SecretKey'];
        $host = $param['host'];
        unset($param['SecretKey']);
        unset($param['host']);
        ksort($param);
        $signStr = "GET" . $host . "/?";
        foreach ( $param as $key => $value ) {
            $signStr = $signStr . $key . "=" . $value . "&";
        }
        $signStr = substr($signStr, 0, -1);

        $signature = base64_encode(hash_hmac("sha1", $signStr, $secretKey, true));
        //echo $signature.PHP_EOL;
        // need to install and enable curl extension in php.ini
        $param["Signature"] = $signature;
        $paramStr = "";
        foreach ( $param as $key => $value ) {
            $paramStr = $paramStr . $key . "=" . urlencode($value) . "&";
        }
        $paramStr = substr($paramStr, 0, -1);
        $curl = "https://" . $host . "/?". $paramStr;
        // dump($curl);
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_URL, $curl);
        $output = curl_exec($ch);
        curl_close($ch);
        $response = json_decode($output,true); //返回结果
        return $response['Response']['SendStatusSet'][0];
    }

}